import threading
from concurrent.futures import ThreadPoolExecutor
from numpy import arange
import requests
import sys
import os
from requests.exceptions import *
import json
import hashlib

sys.path.append(
    os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
)

import spider_config
from model.park_location_record import ParkRecord
from database.park_location_record_table import ParkRecordTable
from common.logger import logger
from proxy.tunnel_proxy_service_qg import TunnelProxyService_QG
from proxy.shared_proxy_service import SharedProxyService
from account.epark_account_service import EParkAccountService
import common.http as http
import time
from threading import Timer

shared_proxy_service = SharedProxyService("shared", 120)

proxy = TunnelProxyService_QG().take(spider_config.jie_park_id).build()

lock = threading.RLock()

# 中国纬度范围: 3.86°N - 53.55°N
# 中国经度范围: 73.66°E - 135.05°E


def requests_jie_park_records(lat, lon):
    url = "https://psbg.jparking.cn/cw-gateway/park-search/v4/near_park"

    headers = {
        "Host": "psbg.jparking.cn",
        "Content-Type": "application/json;charset=utf-8",
    }

    # {"pageIndex":1,"userLatitude":"0.0000000000","longitude":"116.397357","latitude":"39.908879","filter":[],"distance":5000,"userLongitude":"0.0000000000","pageSize":9999}

    pageIndex = 0

    while True:
        pageIndex += 1
        data = {
            "pageIndex": pageIndex,
            "userLatitude": "0.0000000000",
            "longitude": lon,
            "latitude": lat,
            "filter": [],
            "distance": 50000,
            "userLongitude": "0.0000000000",
            "pageSize": 1000,
        }

        rsp = requests.post(url, headers=headers, json=data)

        rspJson = rsp.json()

        if rspJson["code"] != "0":
            logger.error(f"{lat:.2f},{lon:.2f} 请求失败: {rspJson}")
            return

        count = len(rspJson["data"]["list"])

        if count == 0:
            break

        logger.info(f"{lat:.2f},{lon:.2f} - {pageIndex} 请求成功: {count}条数据")

        with lock:
            try:
                with ParkRecordTable() as table:
                    insert_count = 0
                    for item in rspJson["data"]["list"]:
                        record = ParkRecord()
                        record.park_code = item["parkCode"]
                        record.lat = item["latitude"]
                        record.lon = item["longitude"]
                        record.park_name = item["parkName"]
                        if "cityName" in item:
                            record.address += item["cityName"]
                        if "canton" in item:
                            record.address += item["canton"]
                        if "address" in item:
                            record.address += item["address"]
                        record.platform_id = spider_config.jie_park_id
                        if not table.exist("park_code", record.park_code):
                            table.insert(record)
                            insert_count += 1

                    if insert_count > 0:
                        logger.success(f"插入{insert_count}条数据")

                    table.commit()
            except Exception as e:
                logger.exception(e)


def requests_ydt_park_records(lat, lon):
    url = "https://wxydt.yidianting.xin/user/park/listParks4Mini.do"

    params = {
        "gpsX": lon,
        "gpsY": lat,
        "radius": 50000,
        "lgltType": "gaode",
        "isDrag": "false",
        "uiurl": "",
    }

    rsp = requests.post(url, params=params)
    rspJson = rsp.json()

    # logger.info(f"{rspJson['code']} : {i}")

    if rspJson["message"] != "ok":
        logger.error(f"{lat:.2f},{lon:.2f} 请求失败: {rspJson}")
        return

    count = len(rspJson["data"])

    if count == 0:
        return

    logger.info(f"{lat:.2f},{lon:.2f} 请求成功: {count}条数据")

    with lock:
        try:
            with ParkRecordTable() as table:
                insert_count = 0
                for item in rspJson["data"]:
                    record = ParkRecord()
                    record.park_id = item["parkId"]
                    record.park_code = item["parkCode"]
                    record.lat = item["gpsy"]
                    record.lon = item["gpsx"]
                    record.park_name = item["name"]
                    record.address = item["address"]
                    record.platform_id = spider_config.ydt_park_id
                    if not table.exist("park_id", record.park_id):
                        table.insert(record)
                        insert_count += 1

                if insert_count > 0:
                    logger.success(f"插入{insert_count}条数据")

                table.commit()
        except Exception as e:
            logger.error(e)


def request_etcp_park_records(lat, lon):
    global lock

    url = "https://api-c-prod.etcp.cn/map/service/search/surrounding/parking/list/mini"

    params = {
        "distance": 3000,
        "onlinePayOnly": 0,
        "queryType": 1,
        "lat": lat,
        "lon": lon,
        "size": 100,
        "ak": "etcp",
    }

    rsp = requests.get(url, params=params)
    rspJson = rsp.json()

    if rspJson["code"] != 0:
        logger.error(f"请求失败: {rspJson['message']}")
        return

    if len(rspJson["data"]) == 0:
        return

    with lock:
        with ParkRecordTable() as table:
            for item in rspJson["data"]:
                record = ParkRecord()
                record.park_id = item["id"]
                record.lat = item["lat"]
                record.lon = item["lon"]
                record.park_name = item["parkingName"]
                record.platform_id = spider_config.etcp_park_id
                if not table.exist("park_id", record.park_id):
                    table.insert(record)

            table.commit()

def getSharedProxy(platformId: int):
    global shared_proxy_service
    with lock:
        return shared_proxy_service.take(platformId).build()

def request_epark_park_records(lat, lon):
    
    headers = {
        "Host": "wx.ebopark.com",
        "Cookie": "PHPSESSID=m4is5bhhoavjprt14fk0l2pl53;",
        "Content-Type": "application/x-www-form-urlencoded"
    }

    url = f"https://wx.ebopark.com/App/Navigation/getRangePark"

    try:
        
        retry = 0
        max_retry = 3
        
        while True:
            data = {
                "lat": lat,
                "lng": lon,
                "isEboPark": 0,
                "page": 1,
                "isSortByDistance": 0,
                "isSortByIdleCnt": 1,
                "isSortByPrice": 0,
                "pageSize": 30,
                "tag": ""
            }

            data = "&".join([f"{key}={value}" for key, value in data.items()])

            try:
                rsp = http.post(
                    url, headers=headers, data=data, proxies=getSharedProxy(spider_config.epark_park_id), timeout=5
                )
                
            except Exception as e:
                retry += 1
                if retry > max_retry:
                    raise e
                continue
            
            if rsp.status_code != 200:
                if retry < max_retry:
                    retry += 1
                    continue
                logger.error(f"请求失败: {rsp.status_code}")
                return

            rspJson = rsp.json()

            if rspJson["state"] != 0:
                raise RequestException(rspJson)
            
            logger.debug(rspJson)

            items = rspJson["result"]["parkInfos"]

            if len(items) == 0:
                return

            with lock:
                with ParkRecordTable() as table:
                    insert_count = 0
                    for item in items:
                        record = ParkRecord()
                        record.park_code = item["parkCode"]
                        record.lat = item["latitude"]
                        record.lon = item["longitude"]
                        record.park_name = item["parkName"]
                        record.address = item["parkAddr"]
                        record.platform_id = spider_config.epark_park_id

                        if not table.exist("park_code", record.park_code):
                            table.insert(record)
                            insert_count += 1

                    if insert_count > 0:
                        logger.success(f"插入{insert_count}条数据")

                    table.commit()
    except Exception as e:
        logger.error(repr(e))


def request_yima_park_records():
    global lock

    url = f"https://m.bolink.club/capp/api/park/getnearpark"

    headers = {
        "Host": "m.bolink.club",
        "Content-Type": "application/json",
        "token": "3714D32AE0542F773512647815533078D6DCC8933604FC469AC3711A45459E5F",
    }
    # {"lat":34.29317855834961,"lon":108.9471206665039,"dis":500,"pageNum":1,"pageSize":900000}
    data = {
        "lat": 34.29317855834961,
        "lon": 108.9471206665039,
        "dis": 500,
        "pageNum": 1,
        "pageSize": 900000,
    }

    try:
        rsp = requests.post(url, json=data, headers=headers)
        rspJson = rsp.json()

        if rspJson["status"] != 200:
            logger.error(f"请求失败: {rspJson['message']}")
            return

        total = len(rspJson["data"])
        logger.info(total)

        if not rspJson["data"]:
            return

        index = 1

        with ParkRecordTable() as table:
            for item in rspJson["data"]:
                record = ParkRecord()
                record.park_id = item["parkId"]
                record.park_code = item["unionId"]
                record.lat = item["lat"]
                record.lon = item["lng"]
                record.park_name = item["name"]
                record.address = item["address"]
                record.platform_id = spider_config.yima_park_id
                #if not table.exist("park_id", record.park_id):
                table.insert(record)
                logger.info(f"{index}/{total}")
                index += 1
            table.commit()
    except Exception as e:
        logger.exception(e)


def request_su_park_records(lat, lon):
    global lock

    url = f"https://cloud.keytop.cn/member-center/service/front/v2/parking-lot/findParkingLots"

    headers = {
        "Host": "cloud.keytop.cn",
        "Content-Type": "application/json",
        "accessToken": "pr-rPuCj6z_ioMA4ptLC0iXRqP7qeSmVdrXWEuwm1mfkfxv55PmdjrizVLrAi2J2uXXKOLla1s8dkEpNGVkAujw7NPvoZ90pOTkgz-J4eOjQKah06bouBwhcs7RkpTHegk56p3gNrs_lN9d3bw_g6PmVx9I5wjOpUckjWq_02Uw=",
    }
    
    data = {
        "longitude" : lon,
        "latitude" : lat,
        "enableInvoice" : None,
        "enablePostPaid" : None,
        "lotTypeCodes" : []
    }

    retry = 0
    max_retry = 5

    while True:
        try:
            time.sleep(2)
            rsp = requests.post(url, json=data, headers=headers)
            rspJson = rsp.json()

            if rspJson["code"] != 2000:
                logger.error(f"请求失败: {rspJson['message']}")
                return

            logger.info(len(rspJson["data"]))

            if not rspJson["data"]:
                return

            with lock:
                with ParkRecordTable() as table:
                    for item in rspJson["data"]:
                        record = ParkRecord()
                        record.park_id = item["id"]
                        record.lat = item["latitude"]
                        record.lon = item["longitude"]
                        record.park_name = item["keyword"]
                        record.address = item["address"]
                        record.platform_id = spider_config.su_park_id
                        if not table.exist("park_id", record.park_id):
                            table.insert(record)
                    table.commit()
            return
        except Exception as e:
            logger.error(repr(e))
            retry += 1
            if(retry > max_retry):
                return

def request_su_park_by_id():
    global lock

    startId = 36117
    maxId = 99999

    for id in range(startId, maxId):

        url = f"https://cloud.keytop.cn/member-center/service/front/v2/parking-lot/getParkingLotDetail?id={id}"

        headers = {
            "Host": "cloud.keytop.cn",
            "Content-Type": "application/json",
            "accessToken": "pr-rPuCj6z_ioMA4ptLC0iXRqP7qeSmVdrXWEuwm1mdVCMo3agzXlshjEjIYj4cyMuy5RQWHHcsCNdMP6lN0p-Q1XmNJsFxxVuIsTQfYM1bSybHzPn5jEj6zx5mnpCdXevVYSw3KRICGkbvVNDGS0ApAPJphKKt47AkEYwWQk7Q=",
        }
        
        retry = 0
        max_retry = 5

        while True:
            try:
                time.sleep(1.5)
                rsp = requests.get(url, headers=headers)
                rspJson = rsp.json()

                if rspJson["code"] != 2000:
                    logger.error(f"请求失败: {rspJson['message']}")
                    break

                if not rspJson["data"]:
                    break

                logger.info(rspJson["data"])

                with ParkRecordTable() as table:
                    item = rspJson["data"]
                    record = ParkRecord()
                    record.park_id = item["id"]
                    record.lat = item["latitude"]
                    record.lon = item["longitude"]
                    record.park_name = item["keyword"]
                    record.address = item["address"]
                    record.platform_id = spider_config.su_park_id
                    table.insert(record)
                    table.commit()
                break
            except Exception as e:
                logger.error(repr(e))
                retry += 1
                if(retry > max_retry):
                    break
            
def start(platform_id: int):
    
    if platform_id == spider_config.yima_park_id:
        request_yima_park_records()
        return
        
    if platform_id == spider_config.su_park_id:
        request_su_park_by_id()
        return
    
    max_workers = 1

    lon_min = 85
    lon_max = 135

    lat_min = 18
    lat_max = 50

    lon_range = arange(lon_min, lon_max, 0.3)
    lat_range = arange(lat_min, lat_max, 0.3)

    start_time = time.time()

    for lon in lon_range:
        # 打印当前进度百分比，保留两位小数
        scale = (lon - lon_min) / (lon_max - lon_min)
        logger.info(
            f"lon: {lon}, progress: {scale * 100:.2f} %"
        )
        if scale > 0:
            logger.info(f"预计剩余:{(time.time() - start_time) / scale * (1 - scale):.2f}秒")
        thread_pool = ThreadPoolExecutor(max_workers=max_workers)
        for lat in lat_range:
            # 测试位置
            # lat = 34.233266
            # lon = 108.984138

            if platform_id == spider_config.jie_park_id:
                thread_pool.submit(requests_jie_park_records, lat, lon)
            elif platform_id == spider_config.ydt_park_id:
                thread_pool.submit(requests_ydt_park_records, lat, lon)
            elif platform_id == spider_config.etcp_park_id:
                thread_pool.submit(request_etcp_park_records, lat, lon)
            elif platform_id == spider_config.epark_park_id:
                thread_pool.submit(request_epark_park_records, lat, lon)
            elif platform_id == spider_config.su_park_id:
                thread_pool.submit(request_su_park_records, lat, lon)
        thread_pool.shutdown(wait=True)

if __name__ == "__main__":
    start(spider_config.su_park_id)
